import java.awt.Graphics2D;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.imageio.ImageIO;

public class UtilImage {

	public static float dividePixels = 255;

	static boolean evitaBackground = false;

	public static BufferedImage recuperaImagem(String caminho) {
		try {
			File f = new File(caminho);
			BufferedImage image = ImageIO.read(f);
			return image;
		} catch (Exception e) {
			// System.out.println(caminho);
			// e.printStackTrace();
			return null;
		}
	}

	public static double[][] recuperaImagemCinza(String caminho) {
		try {
			File f = new File(caminho);
			BufferedImage image = ImageIO.read(f);
			double[][] retorno = new double[image.getHeight()][image.getWidth()];
			for (int i = 0; i < image.getHeight(); i++) {
				for (int j = 0; j < image.getWidth(); j++) {
					double[] tmp = new double[1];
					image.getRaster().getPixel(j, i, tmp);
					retorno[i][j] = tmp[0];
				}
			}
			return retorno;
		} catch (Exception e) {
			// System.out.println(caminho);
			// e.printStackTrace();
			return null;
		}
	}

	public static double[][] recuperaImagemCinza(BufferedImage image,
			double escala) {
		try {
			double[][] retorno = new double[image.getHeight()][image.getWidth()];
			for (int i = 0; i < image.getHeight(); i++) {
				for (int j = 0; j < image.getWidth(); j++) {
					double[] tmp = new double[1];
					image.getRaster().getPixel(j, i, tmp);
					retorno[i][j] = tmp[0] / escala;
				}
			}
			return retorno;
		} catch (Exception e) {
			// System.out.println(caminho);
			// e.printStackTrace();
			return null;
		}
	}

	public static double[][][] recuperaImagemColorida(String caminho) {
		try {
			File f = new File(caminho);
			BufferedImage image = ImageIO.read(f);
			double[][][] retorno = new double[3][image.getHeight()][image
					.getWidth()];
			for (int i = 0; i < image.getHeight(); i++) {
				for (int j = 0; j < image.getWidth(); j++) {
					double[] tmp = new double[3];
					image.getRaster().getPixel(j, i, tmp);
					retorno[0][i][j] = tmp[0];
					retorno[1][i][j] = tmp[1];
					retorno[2][i][j] = tmp[2];
				}
			}
			return retorno;
		} catch (Exception e) {
			// System.out.println(caminho);
			// e.printStackTrace();
			return null;
		}
	}

	public static void preencheImagemSkinMLP(String caminho,
			String caminhoMascara, String imagem, ArrayList<double[]> skin,
			ArrayList<double[]> nonSkin, boolean isSkin, int nonSkinRestantes) {
		try {
			if (!isSkin) {
				int totalImagens = (skin.size() - nonSkin.size())
						/ nonSkinRestantes;
				File f = new File(caminho + imagem);
				BufferedImage image = ImageIO.read(f);
				ArrayList<double[]> nonSkinTmp = new ArrayList<double[]>();
				for (int y = 0; y < image.getHeight(); y++) {
					for (int x = 0; x < image.getWidth(); x++) {
						double[] tmp = new double[3];
						image.getRaster().getPixel(x, y, tmp);

						double[] elemento = new double[3];
						elemento[0] = (tmp[0] - 128) / dividePixels;
						elemento[1] = (tmp[1] - 128) / dividePixels;
						elemento[2] = (tmp[2] - 128) / dividePixels;

						nonSkinTmp.add(elemento);
					}
				}
				Collections.shuffle(nonSkinTmp);
				for (int i = 0; i < totalImagens && i < nonSkinTmp.size(); i++) {
					nonSkin.add(nonSkinTmp.get(i));
				}
			} else {
				File f = new File(caminho + imagem);
				BufferedImage image = ImageIO.read(f);
				String mascara = imagem.split("\\.")[0];
				File f2 = new File(caminhoMascara + mascara + ".bmp");
				BufferedImage mask = ImageIO.read(f2);
				for (int y = 0; y < image.getHeight(); y++) {
					for (int x = 0; x < image.getWidth(); x++) {
						double[] m = new double[1];
						mask.getRaster().getPixel(x, y, m);
						double[] tmp = new double[3];
						image.getRaster().getPixel(x, y, tmp);

						double[] elemento = new double[3];
						elemento[0] = (tmp[0] - 128) / dividePixels;
						elemento[1] = (tmp[1] - 128) / dividePixels;
						elemento[2] = (tmp[2] - 128) / dividePixels;

						if (m[0] != 0) {
							skin.add(elemento);
						}
					}
				}
			}
			// }
		} catch (Exception e) {
			System.out.println(caminho);
			System.out.println(imagem);
			// e.printStackTrace();
		}
	}

	public static double[][][] recuperaImagemRedimensionando(String caminho,
			int largura, int altura, boolean normaliza) throws Exception {
		try {
			File f = new File(caminho);
			BufferedImage image = redimensionaImagem(ImageIO.read(f), largura,
					altura);
			double[][][] imagem = new double[3][image.getHeight()][image
					.getWidth()];
			for (int y = 0; y < image.getHeight(); ++y) {
				for (int x = 0; x < image.getWidth(); ++x) {
					double[] tmp = new double[3];
					image.getRaster().getPixel(x, y, tmp);
					// if(evitaBackground && tmp[0] == 255 && tmp[1] == 255 &&
					// tmp[2] == 255) {
					// imagem[0][y][x] = 0;
					// imagem[1][y][x] = 0;
					// imagem[2][y][x] = 0;
					// } else {
					if (normaliza) {
						imagem[0][y][x] = (tmp[0] - 255) / dividePixels;
						imagem[1][y][x] = (tmp[1] - 255) / dividePixels;
						imagem[2][y][x] = (tmp[2] - 255) / dividePixels;
					} else {
						imagem[0][y][x] = tmp[0];
						imagem[1][y][x] = tmp[1];
						imagem[2][y][x] = tmp[2];
					}
					// }
				}
			}
			return imagem;
		} catch (Exception e) {
			System.out.println(caminho);
			e.printStackTrace();
			return null;
		}
	}

	public static double[][] recuperaImagemRedimensionandoCinza(String caminho,
			int largura, int altura) throws Exception {
		try {
			File f = new File(caminho);
			BufferedImage image = redimensionaImagem(ImageIO.read(f), largura,
					altura);

			ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
			ColorConvertOp op = new ColorConvertOp(cs, null);
			BufferedImage imagemCinza = op.filter(image, null);

			double[][] imagem = new double[image.getHeight()][image.getWidth()];
			for (int y = 0; y < imagemCinza.getHeight(); ++y) {
				for (int x = 0; x < imagemCinza.getWidth(); ++x) {
					double[] tmp = new double[1];
					imagemCinza.getRaster().getPixel(x, y, tmp);
					imagem[y][x] = tmp[0];
				}
			}
			return imagem;
		} catch (Exception e) {
			System.out.println(caminho);
			e.printStackTrace();
			return null;
		}
	}

	public static double[][] recuperaImagemRedimensionandoCinzaMapa(
			String caminho, String caminhoMapa, int largura, int altura)
			throws Exception {
		try {
			File f = new File(caminhoMapa);
			BufferedImage mapa = ImageIO.read(f);
			File f2 = new File(caminho);
			BufferedImage image = ImageIO.read(f2);
			for (int i = 0; i < mapa.getHeight(); i++) {
				for (int j = 0; j < mapa.getWidth(); j++) {
					double[] pixelMapa = new double[3];
					mapa.getRaster().getPixel(j, i, pixelMapa);
					if (pixelMapa[0] == 0 && pixelMapa[1] == 0
							&& pixelMapa[2] == 0) {
						double[] pixel = new double[] { 0, 0, 0 };
						image.getRaster().setPixel(j, i, pixel);
					}
				}
			}

			image = redimensionaImagem(image, largura, altura);

			ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
			ColorConvertOp op = new ColorConvertOp(cs, null);
			BufferedImage imagemCinza = op.filter(image, null);

			double[][] imagem = new double[image.getHeight()][image.getWidth()];
			for (int y = 0; y < imagemCinza.getHeight(); ++y) {
				for (int x = 0; x < imagemCinza.getWidth(); ++x) {
					double[] tmp = new double[1];
					imagemCinza.getRaster().getPixel(x, y, tmp);
					imagem[y][x] = tmp[0];
				}
			}
			return imagem;
		} catch (Exception e) {
			System.out.println(caminho);
			e.printStackTrace();
			return null;
		}
	}

	public static List<BufferedImage> recuperaImagemDividindo(String caminho,
			int largura, int altura, int escala) throws Exception {
		try {
			List<BufferedImage> retorno = new ArrayList<BufferedImage>();
			File f = new File(caminho);

			BufferedImage imageOriginal = ImageIO.read(f);
			ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
			ColorConvertOp op = new ColorConvertOp(cs, null);
			BufferedImage imagemCinzaOriginal = op.filter(imageOriginal, null);

			for (int y = 0; y < imagemCinzaOriginal.getHeight(); y += escala) {
				for (int x = 0; x < imagemCinzaOriginal.getWidth(); x += escala) {
					BufferedImage imagemTmp = new BufferedImage(escala, escala,
							imagemCinzaOriginal.getType());
					for (int i = 0; i < escala; i++) {
						for (int j = 0; j < escala; j++) {
							double[] pixel = new double[1];
							imagemCinzaOriginal.getRaster().getPixel(x + i,
									y + j, pixel);
							imagemTmp.getRaster().setPixel(i, j, pixel);
						}
					}
					BufferedImage image = redimensionaImagem(imagemTmp,
							largura, altura);
					retorno.add(image);
				}
			}

			return retorno;
		} catch (Exception e) {
			System.out.println(caminho);
			e.printStackTrace();
			return null;
		}
	}

	public static double[][] recuperaImagemRedimensionandoCinzaFiltrando(
			String caminho, String caminhoFiltro, int largura, int altura)
			throws Exception {
		try {
			BufferedImage entrada = ImageIO.read(new File(caminho));
			BufferedImage filtro = ImageIO.read(new File(caminhoFiltro));
			for (int y = 0; y < entrada.getHeight(); ++y) {
				for (int x = 0; x < entrada.getWidth(); ++x) {
					double[] tmp = new double[3];
					filtro.getRaster().getPixel(x, y, tmp);
					if (tmp[0] == 0 && tmp[1] == 0 && tmp[2] == 0) {
						entrada.getRaster().setPixel(x, y,
								new double[] { 0, 0, 0 });
					}
				}
			}

			BufferedImage image = redimensionaImagem(entrada, largura, altura);

			ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
			ColorConvertOp op = new ColorConvertOp(cs, null);
			BufferedImage imagemCinza = op.filter(image, null);

			double[][] imagem = new double[image.getHeight()][image.getWidth()];
			for (int y = 0; y < imagemCinza.getHeight(); ++y) {
				for (int x = 0; x < imagemCinza.getWidth(); ++x) {
					double[] tmp = new double[1];
					imagemCinza.getRaster().getPixel(x, y, tmp);
					imagem[y][x] = tmp[0];
				}
			}
			return imagem;
		} catch (Exception e) {
			System.out.println(caminho);
			System.out.println(caminhoFiltro);
			e.printStackTrace();
			return null;
		}
	}

	public static double[][] recuperaImagemRedimensionandoNivelCor(
			String caminho, int largura, int altura, int nivel)
			throws Exception {
		try {
			File f = new File(caminho);
			BufferedImage image = redimensionaImagem(ImageIO.read(f), largura,
					altura);

			double[][] imagem = new double[image.getHeight()][image.getWidth()];
			for (int y = 0; y < image.getHeight(); ++y) {
				for (int x = 0; x < image.getWidth(); ++x) {
					double[] tmp = new double[3];
					image.getRaster().getPixel(x, y, tmp);
					imagem[y][x] = tmp[nivel];
				}
			}
			return imagem;
		} catch (Exception e) {
			System.out.println(caminho);
			e.printStackTrace();
			return null;
		}
	}

	public static BufferedImage redimensionaImagem(BufferedImage image,
			int largura, int altura) {
		BufferedImage retorno = new BufferedImage(largura, altura,
				image.getType());
		retorno.createGraphics().drawImage(image, 0, 0, largura, altura, 0, 0,
				image.getWidth(), image.getHeight(), null);
		return retorno;
	}

	/**
	 * Recupera os momentos da imagem baseado no artigo Similarity of Color
	 * Images
	 * 
	 * @param imagem
	 * @return
	 */
	public static double[] momentos(double[][][] imagem, boolean momento) {
		if (momento) {
			double[] retorno = new double[imagem.length * 3];
			int tamanho = imagem[0].length * imagem[0][0].length;
			// Calculando o fator E
			for (int k = 0; k < imagem.length; k++) {
				for (int i = 0; i < imagem[0].length; i++) {
					for (int j = 0; j < imagem[0][0].length; j++) {
						retorno[k] += imagem[k][i][j];
					}
				}
				retorno[k] = retorno[k] / tamanho;
			}

			// Calculando sigma
			for (int k = imagem.length; k < imagem.length * 2; k++) {
				for (int i = 0; i < imagem[0].length; i++) {
					for (int j = 0; j < imagem[0][0].length; j++) {
						retorno[k] += Math.pow(imagem[k % imagem.length][i][j]
								- retorno[k % imagem.length], 2);
					}
				}
				retorno[k] = retorno[k] / tamanho;
				retorno[k] = Math.sqrt(retorno[k]);
			}

			// Calculando s
			for (int k = imagem.length * 2; k < imagem.length * 3; k++) {
				for (int i = 0; i < imagem[0].length; i++) {
					for (int j = 0; j < imagem[0][0].length; j++) {
						retorno[k] += Math.pow(imagem[k % imagem.length][i][j]
								- retorno[k % imagem.length], 3);
					}
				}
				retorno[k] = retorno[k] / tamanho;
				if (retorno[k] < 0) {
					retorno[k] = Math.pow(-retorno[k], 1.0 / 3.0);
					retorno[k] = -retorno[k];
				} else {
					retorno[k] = Math.pow(retorno[k], 1.0 / 3.0);
				}
			}

			/*
			 * System.out.println("Imprimindo momento"); for(int i = 0; i <
			 * retorno.length; i++) { System.out.print(retorno[i]+" "); }
			 */

			return retorno;
		} else {
			double[] retorno = new double[imagem.length * imagem[0].length
					* imagem[0][0].length];
			int cont = 0;
			for (int k = 0; k < imagem.length; k++) {
				for (int i = 0; i < imagem[0].length; i++) {
					for (int j = 0; j < imagem[0][0].length; j++) {
						retorno[cont] = imagem[k][i][j];
						cont++;
					}
				}
			}
			return retorno;
		}
	}

	public static BufferedImage preencheImagem2(String caminho, int largura,
			int altura) throws Exception {
		try {
			File f = new File(caminho);
			BufferedImage image = redimensionaImagem(ImageIO.read(f), largura,
					altura);
			return image;
		} catch (Exception e) {
			System.out.println(caminho);
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * Cityblock
	 * 
	 * @param d1
	 * @param d2
	 * @return
	 */
	public static double distancia2(double[] d1, double[] d2) {
		double retorno = 0;
		for (int i = 0; i < d1.length; i++) {
			retorno = retorno + Math.abs(d1[i] - d2[i]);
		}
		return retorno;
	}

	public static double distancia2(double[] d1, double[] d2, double pot) {
		double retorno = 0;
		for (int i = 0; i < d1.length; i++) {
			retorno = retorno + Math.pow(Math.abs(d1[i] - d2[i]), pot);
		}
		Math.pow(retorno, 1 / pot);
		return retorno;
	}

	/**
	 * Cityblock
	 * 
	 * @param d1
	 * @param d2
	 * @return
	 */
	public static double distancia2(double[][][] d1, double[][][] d2) {
		double retorno = 0;
		for (int i = 0; i < d1.length; i++) {
			for (int j = 0; j < d1[0].length; j++) {
				for (int k = 0; k < d1[0][0].length; k++) {
					retorno = retorno + Math.abs(d1[i][j][k] - d2[i][j][k]);
				}
			}
		}
		return retorno;
	}

	public static double distancia2(double[][] d1, double[][] d2) {
		double retorno = 0;
		for (int i = 0; i < d1.length; i++) {
			for (int j = 0; j < d1[0].length; j++) {
				retorno = retorno + Math.abs(d1[i][j] - d2[i][j]);
			}
		}
		return retorno;
	}

	/**
	 * Similaridade coseno
	 * 
	 * @param d1
	 * @param d2
	 * @return
	 */
	public static double distanciaCos(double[][][] d1, double[][][] d2) {
		double retorno = 0;
		double numerador = 0;
		double denominador1 = 0;
		double denominador2 = 0;
		for (int i = 0; i < d1.length; i++) {
			for (int j = 0; j < d1[0].length; j++) {
				for (int k = 0; k < d1[0][0].length; k++) {
					numerador += d1[i][j][k] * d2[i][j][k];
					denominador1 += Math.pow(d1[i][j][k], 2);
					denominador2 += Math.pow(d2[i][j][k], 2);
				}
			}
		}
		retorno = numerador
				/ (Math.sqrt(denominador1) * Math.sqrt(denominador2));
		return retorno;
	}

	/**
	 * Cityblock
	 * 
	 * @param d1
	 * @param d2
	 * @return
	 */
	public static double distancia2Considera(double[][][] d1, double[][][] d2,
			double[][][] multiplica) {
		double retorno = 0;
		for (int i = 0; i < d1.length; i++) {
			for (int j = 0; j < d1[0].length; j++) {
				for (int k = 0; k < d1[0][0].length; k++) {
					retorno = retorno
							+ (Math.abs(d1[i][j][k] - d2[i][j][k]) * multiplica[i][j][k]);
				}
			}
		}
		return retorno;
	}
	
	public static double distancia2Considera(double[][] d1, double[][] d2,
			double[][] multiplica) {
		double retorno = 0;
		for (int i = 0; i < d1.length; i++) {
			for (int j = 0; j < d1[0].length; j++) {
				retorno = retorno
					+ (Math.abs(d1[i][j] - d2[i][j]) * multiplica[i][j]);
			}
		}
		return retorno;
	}

	public static double distancia2(double[][][] d1, double[][][] d2,
			boolean imprime) {
		double retorno = 0;
		for (int i = 0; i < d1.length; i++) {
			for (int j = 0; j < d1[0].length; j++) {
				for (int k = 0; k < d1[0][0].length; k++) {
					double diferenca = Math.abs(d1[i][j][k] - d2[i][j][k]);
					retorno = retorno + diferenca;
					if (imprime) {
						System.out.print(diferenca + " ");
					}
				}
				if (imprime) {
					System.out.println();
				}
			}
		}
		return retorno;
	}

	public static void distancia2(double[][][] d1, double[][][] d2,
			double[][][] retorno) {
		for (int i = 0; i < d1.length; i++) {
			for (int j = 0; j < d1[0].length; j++) {
				for (int k = 0; k < d1[0][0].length; k++) {
					double diferenca = Math.abs(d1[i][j][k] - d2[i][j][k]);
					retorno[i][j][k] += diferenca;
				}
			}
		}
	}

	public static double distanciaEuclidiana(double[] d1, double[] d2) {
		double retorno = 0;
		for (int i = 0; i < d1.length; i++) {
			retorno = retorno + Math.pow(d1[i] - d2[i], 2);
		}
		return Math.sqrt(retorno);
	}
	
	public static double distanciaEuclidiana(double[][] d1, double[][] d2) {
		double retorno = 0;
		for (int i = 0; i < d1.length; i++) {
			for (int j = 0; j < d1[0].length; j++) {
				retorno = retorno + Math.pow(d1[i][j] - d2[i][j], 2);
			}
		}
		return Math.sqrt(retorno);
	}

	public static double distancia2Ponderada(double[] d1, double[] d2,
			double[] peso) {
		double retorno = 0;
		for (int i = 0; i < d1.length; i++) {
			retorno = retorno + (1 / (Math.abs(d1[i] - d2[i])) * peso[i]);
		}
		return retorno;
	}

	public static double distancia2Selecionada(double[] d1, double[] d2,
			int[] posicoes) {
		double retorno = 0;
		for (int i = 0; i < posicoes.length; i++) {
			retorno = retorno + Math.abs(d1[posicoes[i]] - d2[posicoes[i]]);
		}
		return retorno;
	}

	public static double[] media(double[][] entradas) {
		double[] media = new double[entradas[0].length];

		for (double[] entrada : entradas) {
			for (int i = 0; i < entrada.length; i++) {
				media[i] += (entrada[i] / entradas.length);
			}
		}

		return media;
	}

	public static double[] variancia(double[][] entradas, double[] media) {
		double[] variancia = new double[entradas[0].length];

		for (double[] entrada : entradas) {
			for (int i = 0; i < entrada.length; i++) {
				variancia[i] += (Math.pow(entrada[i] - media[i], 2) / (entradas.length - 1));
			}
		}

		return variancia;
	}

	public static double calculaArea(double[][] els) {
		double area = 0;
		for (int i = 1; i < els.length; i++) {
			// System.out.println(els[i][0]+" | "+els[i][1]);
			double base = els[i][1] - els[i - 1][1];
			double alturaTriangulo = els[i][0] - els[i - 1][0];
			double alturaRetangulo = els[i - 1][0];
			double areaTriangulo = (base * alturaTriangulo) / 2;
			double areaRetangulo = base * alturaRetangulo;
			area = area + areaTriangulo + areaRetangulo;
		}
		return area;
	}

	public static double[] recuperaArrayImagem(String caminho, int tamanho) {
		try {
			File f = new File(caminho);
			BufferedImage image = redimensionaImagem(ImageIO.read(f), tamanho,
					tamanho);
			double[] imagemSaida = new double[image.getHeight()
					* image.getWidth() * 3];
			for (int y = 0; y < image.getHeight(); ++y) {
				for (int x = 0; x < image.getWidth(); ++x) {
					double[] tmp = new double[3];
					image.getRaster().getPixel(x, y, tmp);
					imagemSaida[(y * tamanho) + x] = (tmp[0] - 128)
							/ dividePixels;
					imagemSaida[(tamanho * tamanho) + (y * tamanho) + x] = (tmp[1] - 128)
							/ dividePixels;
					imagemSaida[((tamanho * tamanho) * 2) + (y * tamanho) + x] = (tmp[2] - 128)
							/ dividePixels;
				}
			}
			return imagemSaida;
		} catch (Exception e) {
			System.out.println(caminho);
			e.printStackTrace();
			return null;
		}
	}

	public static void preencheImagem(String caminho,
			ArrayList<double[][][]> entrada, ArrayList<double[]> saida,
			int tamanho) {
		try {
			File f = new File(caminho);
			BufferedImage image = redimensionaImagem(ImageIO.read(f), tamanho,
					tamanho);
			// System.out.println(image.getType());
			double[][][] imagem = new double[3][image.getHeight()][image
					.getWidth()];
			double[] imagemSaida = new double[image.getHeight()
					* image.getWidth() * 3];
			// for(int reducao = 0; reducao <= 255; reducao += 51) {
			for (int y = 0; y < image.getHeight(); ++y) {
				for (int x = 0; x < image.getWidth(); ++x) {
					double[] tmp = new double[3];
					image.getRaster().getPixel(x, y, tmp);
					if (evitaBackground && tmp[0] == 255 && tmp[1] == 255
							&& tmp[2] == 255) {
						imagemSaida[(y * tamanho) + x] = 0;
						imagemSaida[(tamanho * tamanho) + (y * tamanho) + x] = 0;
						imagemSaida[((tamanho * tamanho) * 2) + (y * tamanho)
								+ x] = 0;
						imagem[0][y][x] = 0;
						imagem[1][y][x] = 0;
						imagem[2][y][x] = 0;
						// tmp[0] = tmp[0] - reducao;
						// tmp[1] = tmp[1] - reducao;
						// tmp[2] = tmp[2] - reducao;
					} else {
						imagemSaida[(y * tamanho) + x] = (tmp[0] - 128)
								/ dividePixels;
						imagemSaida[(tamanho * tamanho) + (y * tamanho) + x] = (tmp[1] - 128)
								/ dividePixels;
						imagemSaida[((tamanho * tamanho) * 2) + (y * tamanho)
								+ x] = (tmp[2] - 128) / dividePixels;
						imagem[0][y][x] = (tmp[0] - 128) / dividePixels;
						imagem[1][y][x] = (tmp[1] - 128) / dividePixels;
						imagem[2][y][x] = (tmp[2] - 128) / dividePixels;
					}
				}
			}
			entrada.add(imagem);
			saida.add(imagemSaida);
			// }
		} catch (Exception e) {
			System.out.println(caminho);
			e.printStackTrace();
		}
	}

	public static void preencheImagem2(String caminho,
			ArrayList<double[][][]> entrada, ArrayList<double[]> saida,
			int tamanho, int totalSaidas, int posSaida) {
		try {
			File f = new File(caminho);
			BufferedImage image = redimensionaImagem(ImageIO.read(f), tamanho,
					tamanho);
			// System.out.println(image.getType());
			double[][][] imagem = new double[3][image.getHeight()][image
					.getWidth()];
			double[] imagemSaida = new double[totalSaidas];
			for (int i = 0; i < imagemSaida.length; i++) {
				imagemSaida[i] = -1;
			}
			imagemSaida[posSaida] = 1;
			// for(int reducao = 0; reducao <= 255; reducao += 51) {
			for (int y = 0; y < image.getHeight(); ++y) {
				for (int x = 0; x < image.getWidth(); ++x) {
					double[] tmp = new double[3];
					image.getRaster().getPixel(x, y, tmp);
					imagem[0][y][x] = (tmp[0] - 128) / dividePixels;
					imagem[1][y][x] = (tmp[1] - 128) / dividePixels;
					imagem[2][y][x] = (tmp[2] - 128) / dividePixels;
				}
			}
			entrada.add(imagem);
			saida.add(imagemSaida);
			// }
		} catch (Exception e) {
			System.out.println(caminho);
			e.printStackTrace();
		}
	}

	public static void preencheImagem3(String caminho,
			ArrayList<double[][][]> entrada, ArrayList<double[]> saida,
			int tamanho, int totalSaidas, int posSaida) {
		try {
			File f = new File(caminho);
			BufferedImage image = redimensionaImagem(ImageIO.read(f), tamanho,
					tamanho);
			// System.out.println(image.getType());
			double[][][] imagem = new double[3][image.getHeight()][image
					.getWidth()];
			double[] imagemSaida = new double[] { -1, 1 };
			// for(int reducao = 0; reducao <= 255; reducao += 51) {
			for (int y = 0; y < image.getHeight(); ++y) {
				for (int x = 0; x < image.getWidth(); ++x) {
					double[] tmp = new double[3];
					image.getRaster().getPixel(x, y, tmp);
					imagem[0][y][x] = (tmp[0] - 128) / dividePixels;
					imagem[1][y][x] = (tmp[1] - 128) / dividePixels;
					imagem[2][y][x] = (tmp[2] - 128) / dividePixels;
				}
			}
			entrada.add(imagem);
			saida.add(imagemSaida);
			// }
		} catch (Exception e) {
			System.out.println(caminho);
			e.printStackTrace();
		}
	}

	public static void preencheImagem3(String caminho,
			ArrayList<double[][][]> entrada, ArrayList<double[]> saida) {
		try {
			File f = new File(caminho);
			BufferedImage image = ImageIO.read(f);
			// System.out.println(image.getType());
			double[][][] imagem = new double[3][image.getHeight()][image
					.getWidth()];
			double[] imagemSaida = new double[] { -1, 1 };
			// for(int reducao = 0; reducao <= 255; reducao += 51) {
			for (int y = 0; y < image.getHeight(); ++y) {
				for (int x = 0; x < image.getWidth(); ++x) {
					double[] tmp = new double[3];
					image.getRaster().getPixel(x, y, tmp);
					imagem[0][y][x] = (tmp[0] - 128) / dividePixels;
					imagem[1][y][x] = (tmp[1] - 128) / dividePixels;
					imagem[2][y][x] = (tmp[2] - 128) / dividePixels;
				}
			}
			entrada.add(imagem);
			saida.add(imagemSaida);
			// }
		} catch (Exception e) {
			System.out.println(caminho);
			e.printStackTrace();
		}
	}

	public static void preencheImagemMSRF(String caminho,
			String caminhoMascara, String imagem, double[][][] probsSkin,
			double[][][] probsNonSkin, boolean skin, double[] probsSkinR,
			double[] probsSkinG, double[] probsSkinB, double[] probsNonSkinR,
			double[] probsNonSkinG, double[] probsNonSkinB) {
		try {
			if (!skin) {
				File f = new File(caminho + imagem);
				BufferedImage image = ImageIO.read(f);
				for (int y = 0; y < image.getHeight(); ++y) {
					for (int x = 0; x < image.getWidth(); ++x) {
						double[] tmp = new double[3];
						image.getRaster().getPixel(x, y, tmp);
						probsNonSkin[new Double(tmp[0]).intValue()][new Double(
								tmp[1]).intValue()][new Double(tmp[2])
								.intValue()] += 1.0;
						probsNonSkinR[new Double(tmp[0]).intValue()] += 1.0;
						probsNonSkinG[new Double(tmp[1]).intValue()] += 1.0;
						probsNonSkinB[new Double(tmp[2]).intValue()] += 1.0;
					}
				}
			} else {
				File f = new File(caminho + imagem);
				BufferedImage image = ImageIO.read(f);
				String mascara = imagem.split("\\.")[0];
				File f2 = new File(caminhoMascara + mascara + ".bmp");
				BufferedImage mask = ImageIO.read(f2);
				for (int y = 0; y < image.getHeight(); ++y) {
					for (int x = 0; x < image.getWidth(); ++x) {
						double[] m = new double[1];
						mask.getRaster().getPixel(x, y, m);
						double[] tmp = new double[3];
						image.getRaster().getPixel(x, y, tmp);
						if (m[0] == 0) {
							probsNonSkin[new Double(tmp[0]).intValue()][new Double(
									tmp[1]).intValue()][new Double(tmp[2])
									.intValue()] += 1.0;
							probsNonSkinR[new Double(tmp[0]).intValue()] += 1.0;
							probsNonSkinG[new Double(tmp[1]).intValue()] += 1.0;
							probsNonSkinB[new Double(tmp[2]).intValue()] += 1.0;
						} else {
							probsSkin[new Double(tmp[0]).intValue()][new Double(
									tmp[1]).intValue()][new Double(tmp[2])
									.intValue()] += 1.0;
							probsSkinR[new Double(tmp[0]).intValue()] += 1.0;
							probsSkinG[new Double(tmp[1]).intValue()] += 1.0;
							probsSkinB[new Double(tmp[2]).intValue()] += 1.0;
						}
					}
				}
			}
			// }
		} catch (Exception e) {
			System.out.println(caminho);
			System.out.println(imagem);
			// e.printStackTrace();
		}
	}

	public static void preencheImagemBayes(String caminho,
			String caminhoMascara, String imagem, double[][][] probsSkin,
			double[][][] probsNonSkin, boolean skin, double[] probsSkinR,
			double[] probsSkinG, double[] probsSkinB, double[] probsNonSkinR,
			double[] probsNonSkinG, double[] probsNonSkinB, Double[] qtds) {
		try {
			if (!skin) {
				File f = new File(caminho + imagem);
				BufferedImage image = ImageIO.read(f);
				for (int y = 0; y < image.getHeight(); ++y) {
					for (int x = 0; x < image.getWidth(); ++x) {
						double[] tmp = new double[3];
						image.getRaster().getPixel(x, y, tmp);
						probsNonSkin[new Double(tmp[0]).intValue()][new Double(
								tmp[1]).intValue()][new Double(tmp[2])
								.intValue()] += 1.0;
						probsNonSkinR[new Double(tmp[0]).intValue()] += 1.0;
						probsNonSkinG[new Double(tmp[1]).intValue()] += 1.0;
						probsNonSkinB[new Double(tmp[2]).intValue()] += 1.0;
						qtds[1]++;
					}
				}
			} else {
				File f = new File(caminho + imagem);
				BufferedImage image = ImageIO.read(f);
				String mascara = imagem.split("\\.")[0];
				File f2 = new File(caminhoMascara + mascara + ".bmp");
				BufferedImage mask = ImageIO.read(f2);
				for (int y = 0; y < image.getHeight(); ++y) {
					for (int x = 0; x < image.getWidth(); ++x) {
						double[] m = new double[1];
						mask.getRaster().getPixel(x, y, m);
						double[] tmp = new double[3];
						image.getRaster().getPixel(x, y, tmp);
						if (m[0] == 0) {
							probsNonSkin[new Double(tmp[0]).intValue()][new Double(
									tmp[1]).intValue()][new Double(tmp[2])
									.intValue()] += 1.0;
							probsNonSkinR[new Double(tmp[0]).intValue()] += 1.0;
							probsNonSkinG[new Double(tmp[1]).intValue()] += 1.0;
							probsNonSkinB[new Double(tmp[2]).intValue()] += 1.0;
							qtds[1]++;
						} else {
							probsSkin[new Double(tmp[0]).intValue()][new Double(
									tmp[1]).intValue()][new Double(tmp[2])
									.intValue()] += 1.0;
							probsSkinR[new Double(tmp[0]).intValue()] += 1.0;
							probsSkinG[new Double(tmp[1]).intValue()] += 1.0;
							probsSkinB[new Double(tmp[2]).intValue()] += 1.0;
							qtds[0]++;
						}
					}
				}
			}
			// }
		} catch (Exception e) {
			System.out.println(caminho);
			System.out.println(imagem);
			// e.printStackTrace();
		}
	}

	public static void preencheImagemSkinIpyraNet(String caminho,
			String caminhoMascara, String imagem, ArrayList<double[][][]> skin,
			ArrayList<double[][][]> nonSkin, boolean isSkin, int tamanho,
			double percentualMinimoSkin, int nonSkinRestantes) {
		// double dividePixels = 255*16;
		try {
			if (!isSkin) {
				int totalImagens = (skin.size() - nonSkin.size())
						/ nonSkinRestantes;
				File f = new File(caminho + imagem);
				BufferedImage image = ImageIO.read(f);
				ArrayList<double[][][]> nonSkinTmp = new ArrayList<double[][][]>();
				for (int y = 0; y + tamanho < image.getHeight(); y = y
						+ tamanho) {
					for (int x = 0; x + tamanho < image.getWidth(); x = x
							+ tamanho) {
						double[][][] subImagem = new double[3][tamanho][tamanho];
						for (int i = y; i < y + tamanho; i++) {
							for (int j = x; j < x + tamanho; j++) {
								double[] tmp = new double[3];
								image.getRaster().getPixel(j, i, tmp);
								subImagem[0][i - y][j - x] = ((tmp[0]) / dividePixels);// +(0.25/2);
								subImagem[1][i - y][j - x] = ((tmp[1]) / dividePixels);// +(0.25/2);
								subImagem[2][i - y][j - x] = ((tmp[2]) / dividePixels);// +(0.25/2);
							}
						}
						nonSkinTmp.add(subImagem);
					}
				}
				Collections.shuffle(nonSkinTmp);
				for (int i = 0; i < totalImagens && i < nonSkinTmp.size(); i++) {
					nonSkin.add(nonSkinTmp.get(i));
				}
			} else {
				File f = new File(caminho + imagem);
				BufferedImage image = ImageIO.read(f);
				String mascara = imagem.split("\\.")[0];
				File f2 = new File(caminhoMascara + mascara + ".bmp");
				BufferedImage mask = ImageIO.read(f2);
				for (int y = 0; y + tamanho < image.getHeight(); y = y
						+ tamanho) {
					for (int x = 0; x + tamanho < image.getWidth(); x = x
							+ tamanho) {
						double[][][] subImagem = new double[3][tamanho][tamanho];
						double qtdSkin = 0;
						for (int i = y; i < y + tamanho; i++) {
							for (int j = x; j < x + tamanho; j++) {
								double[] m = new double[1];
								mask.getRaster().getPixel(j, i, m);
								double[] tmp = new double[3];
								image.getRaster().getPixel(j, i, tmp);
								subImagem[0][i - y][j - x] = ((tmp[0]) / dividePixels);// +(0.25/2);
								subImagem[1][i - y][j - x] = ((tmp[1]) / dividePixels);// +(0.25/2);
								subImagem[2][i - y][j - x] = ((tmp[2]) / dividePixels);// +(0.25/2);
								if (m[0] != 0) {
									qtdSkin++;
								}
							}
						}
						if (qtdSkin < 1) {
							nonSkin.add(subImagem);
						} else if (qtdSkin
								/ new Integer(tamanho * tamanho).doubleValue() >= percentualMinimoSkin) {
							skin.add(subImagem);
						}

					}
				}
			}
			// }
		} catch (Exception e) {
			System.out.println(caminho);
			System.out.println(imagem);
			// e.printStackTrace();
		}
	}

	public static void preencheImagemNonSkinIpyraNet(String caminho,
			String imagem, ArrayList<double[][][]> nonSkin, int tamanho) {
		// double dividePixels = 255*16;
		try {
			File f = new File(caminho + imagem);
			BufferedImage image = ImageIO.read(f);
			for (int y = 0; y + tamanho < image.getHeight(); y = y + tamanho) {
				for (int x = 0; x + tamanho < image.getWidth(); x = x + tamanho) {
					double[][][] subImagem = new double[3][tamanho][tamanho];
					for (int i = y; i < y + tamanho; i++) {
						for (int j = x; j < x + tamanho; j++) {
							double[] tmp = new double[3];
							image.getRaster().getPixel(j, i, tmp);
							subImagem[0][i - y][j - x] = ((tmp[0]) / dividePixels);// +(0.25/2);
							subImagem[1][i - y][j - x] = ((tmp[1]) / dividePixels);// +(0.25/2);
							subImagem[2][i - y][j - x] = ((tmp[2]) / dividePixels);// +(0.25/2);
						}
					}
					nonSkin.add(subImagem);
				}
			}
		} catch (Exception e) {
			System.out.println(caminho);
			System.out.println(imagem);
			// e.printStackTrace();
		}
	}

	public static void preencheImagemSkinPuraIpyraNet(String caminho,
			String caminhoMascara, String imagem, ArrayList<double[][][]> skin,
			ArrayList<double[][][]> nonSkin, int tamanho,
			double percentualMinimoSkin) {
		// double dividePixels = 255*16;
		try {
			File f = new File(caminho + imagem);
			BufferedImage image = ImageIO.read(f);
			String mascara = imagem.split("\\.")[0];
			File f2 = new File(caminhoMascara + mascara + ".bmp");
			BufferedImage mask = ImageIO.read(f2);
			for (int y = 0; y + tamanho < image.getHeight(); y = y + tamanho) {
				for (int x = 0; x + tamanho < image.getWidth(); x = x + tamanho) {
					double[][][] subImagem = new double[3][tamanho][tamanho];
					double qtdSkin = 0;
					for (int i = y; i < y + tamanho; i++) {
						for (int j = x; j < x + tamanho; j++) {
							double[] m = new double[1];
							mask.getRaster().getPixel(j, i, m);
							double[] tmp = new double[3];
							image.getRaster().getPixel(j, i, tmp);
							subImagem[0][i - y][j - x] = ((tmp[0]) / dividePixels);// +(0.25/2);
							subImagem[1][i - y][j - x] = ((tmp[1]) / dividePixels);// +(0.25/2);
							subImagem[2][i - y][j - x] = ((tmp[2]) / dividePixels);// +(0.25/2);
							if (m[0] != 0) {
								qtdSkin++;
							}
						}
					}
					if (qtdSkin < 1) {
						// nonSkin.add(subImagem);
					} else if (qtdSkin
							/ new Integer(tamanho * tamanho).doubleValue() >= percentualMinimoSkin) {
						skin.add(subImagem);
					}

				}
			}
			// }
		} catch (Exception e) {
			System.out.println(caminho);
			System.out.println(imagem);
			// e.printStackTrace();
		}
	}

	public static void preencheImagem2(String caminho,
			ArrayList<double[][][]> entrada, ArrayList<double[]> saida,
			int tamanhoA, int tamanhoL, int totalSaidas, int posSaida) {
		try {
			File f = new File(caminho);
			BufferedImage image = redimensionaImagem(ImageIO.read(f), tamanhoL,
					tamanhoA);
			// System.out.println(image.getType());
			double[][][] imagem = new double[3][image.getHeight()][image
					.getWidth()];
			double[] imagemSaida = new double[totalSaidas];
			for (int i = 0; i < imagemSaida.length; i++) {
				imagemSaida[i] = -1;
			}
			imagemSaida[posSaida] = 1;
			// for(int reducao = 0; reducao <= 255; reducao += 51) {
			for (int y = 0; y < image.getHeight(); ++y) {
				for (int x = 0; x < image.getWidth(); ++x) {
					double[] tmp = new double[3];
					image.getRaster().getPixel(x, y, tmp);
					imagem[0][y][x] = (tmp[0] - 128) / dividePixels;
					imagem[1][y][x] = (tmp[1] - 128) / dividePixels;
					imagem[2][y][x] = (tmp[2] - 128) / dividePixels;
				}
			}
			entrada.add(imagem);
			saida.add(imagemSaida);
			// }
		} catch (Exception e) {
			System.out.println(caminho);
			e.printStackTrace();
		}
	}

	public static void preencheImagem(String caminho,
			ArrayList<double[][][]> entrada, int tamanho) {
		try {
			File f = new File(caminho);
			BufferedImage image = redimensionaImagem(ImageIO.read(f), tamanho,
					tamanho);
			// System.out.println(image.getType());
			double[][][] imagem = new double[3][image.getHeight()][image
					.getWidth()];
			// for(int reducao = 0; reducao <= 255; reducao += 51) {
			for (int y = 0; y < image.getHeight(); ++y) {
				for (int x = 0; x < image.getWidth(); ++x) {
					double[] tmp = new double[3];
					image.getRaster().getPixel(x, y, tmp);
					if (evitaBackground && tmp[0] == 255 && tmp[1] == 255
							&& tmp[2] == 255) {
						imagem[0][y][x] = 0;
						imagem[1][y][x] = 0;
						imagem[2][y][x] = 0;
						// tmp[0] = tmp[0] - reducao;
						// tmp[1] = tmp[1] - reducao;
						// tmp[2] = tmp[2] - reducao;
					} else {
						imagem[0][y][x] = (tmp[0] - 128) / dividePixels;
						imagem[1][y][x] = (tmp[1] - 128) / dividePixels;
						imagem[2][y][x] = (tmp[2] - 128) / dividePixels;
					}
				}
			}
			entrada.add(imagem);
			// }
		} catch (Exception e) {
			System.out.println(caminho);
			e.printStackTrace();
		}
	}

	public static void pintaCinza(String caminho, double[][] imagem)
			throws Exception {
		try {
			BufferedImage image2 = new BufferedImage(imagem[0].length,
					imagem.length, BufferedImage.TYPE_BYTE_GRAY);
			for (int y = 0; y < imagem.length; ++y) {
				for (int x = 0; x < imagem[0].length; ++x) {
					// System.out.println(tmp[0]+" | "+tmp[0]/256000);
					double[] tmp = new double[] { imagem[y][x] };
					image2.getRaster().setPixel(x, y, tmp);
				}
			}
			ImageIO.write(image2, "bmp", new File(caminho));

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void pinta(String caminho, double[][][] imagem)
			throws Exception {
		try {
			BufferedImage image2 = new BufferedImage(imagem[0][0].length,
					imagem[0].length, 5);
			for (int y = 0; y < imagem.length; ++y) {
				for (int x = 0; x < imagem[0].length; ++x) {
					// System.out.println(tmp[0]+" | "+tmp[0]/256000);
					double[] tmp = new double[] { imagem[0][y][x],
							imagem[1][y][x], imagem[2][y][x] };
					image2.getRaster().setPixel(x, y, tmp);
				}
			}
			ImageIO.write(image2, "jpg", new File(caminho));

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void pintaEscala(String caminho, double[][][] imagem)
			throws Exception {
		try {
			BufferedImage image2 = new BufferedImage(imagem[0][0].length,
					imagem[0].length, 5);
			for (int y = 0; y < imagem[0].length; ++y) {
				for (int x = 0; x < imagem[0][0].length; ++x) {
					// System.out.println(tmp[0]+" | "+tmp[0]/256000);
					double[] tmp = new double[] {
							imagem[0][y][x] * dividePixels + 255,
							imagem[1][y][x] * dividePixels + 255,
							imagem[2][y][x] * dividePixels + 255 };
					image2.getRaster().setPixel(x, y, tmp);
				}
			}
			ImageIO.write(image2, "jpg", new File(caminho));

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void pintaEscala(String caminho, double[][] imagem,
			double multiplica, double soma) throws Exception {
		try {
			BufferedImage image2 = new BufferedImage(imagem[0].length,
					imagem.length, BufferedImage.TYPE_BYTE_GRAY);
			for (int y = 0; y < imagem.length; ++y) {
				for (int x = 0; x < imagem[0].length; ++x) {
					// System.out.println(tmp[0]+" | "+tmp[0]/256000);
					double[] tmp = new double[] { imagem[y][x] * multiplica
							+ soma };
					image2.getRaster().setPixel(x, y, tmp);
				}
			}
			ImageIO.write(image2, "jpg", new File(caminho));

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void pintaCorrigindo(String caminho, double[][][] imagem)
			throws Exception {
		try {
			BufferedImage image2 = new BufferedImage(imagem[0][0].length,
					imagem[0].length, 5);
			for (int y = 0; y < imagem[0].length; ++y) {
				for (int x = 0; x < imagem[0][0].length; ++x) {
					// System.out.println(tmp[0]+" | "+tmp[0]/256000);
					double[] tmp = new double[] { imagem[0][y][x] * 255,
							imagem[1][y][x] * 255, imagem[2][y][x] * 255 };
					image2.getRaster().setPixel(x, y, tmp);
				}
			}
			ImageIO.write(image2, "jpg", new File(caminho));

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void pinta(String caminho, BufferedImage imagem)
			throws Exception {
		try {
			ImageIO.write(imagem, "jpg", new File(caminho));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static BufferedImage redimensionaImagem(String caminho, int largura,
			int altura) {
		try {
			File f = new File(caminho);
			BufferedImage image = ImageIO.read(f);
			BufferedImage retorno = new BufferedImage(largura, altura,
					image.getType());
			retorno.createGraphics().drawImage(image, 0, 0, largura, altura, 0,
					0, image.getWidth(), image.getHeight(), null);
			return retorno;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	public static double[][] inverteMatriz(double[][] entrada) {
		double[][] retorno = new double[entrada[0].length][entrada.length];

		for (int i = 0; i < entrada.length; i++) {
			for (int j = 0; j < entrada[0].length; j++) {
				retorno[j][i] = entrada[i][j];
			}
		}

		return retorno;
	}

	private static boolean contem(int[] elementos, int elemento) {
		for (int i = 0; i < elementos.length; i++) {
			if (elementos[i] == elemento) {
				return true;
			}
		}
		return false;
	}

	public static double[] converteMatriz3ToArray(double[][][] matriz3) {
		double[] arrayRetorno = new double[matriz3.length * matriz3[0].length
				* matriz3[0][0].length];
		int conta = 0;
		for (int i = 0; i < matriz3.length; i++) {
			for (int j = 0; j < matriz3[0].length; j++) {
				for (int k = 0; k < matriz3[0][0].length; k++) {
					arrayRetorno[conta] = matriz3[i][j][k];
					conta++;
				}
			}

		}
		return arrayRetorno;
	}
	
	public static double[] converteMatrizToArray(double[][] matriz3) {
		double[] arrayRetorno = new double[matriz3.length * matriz3[0].length];
		int conta = 0;
		for (int i = 0; i < matriz3.length; i++) {
			for (int j = 0; j < matriz3[0].length; j++) {
					arrayRetorno[conta] = matriz3[i][j];
					conta++;
			}
		}
		return arrayRetorno;
	}

	public static void printMatriz(double[][][] matriz3) {
		System.out.println();
		for (int i = 0; i < matriz3.length; i++) {
			for (int j = 0; j < matriz3[0].length; j++) {
				for (int k = 0; k < matriz3[0][0].length; k++) {
					System.out.print(matriz3[i][j][k] + " ");
				}
				System.out.println();
			}
			System.out.println();
		}
	}

	public static double[][][] mediana(double[][][] imagem, int raio) {
		double[][][] retorno = new double[imagem.length][imagem[0].length][imagem[0][0].length];
		for (int k = 0; k < imagem.length; k++) {
			for (int i = 0; i < imagem[k].length; i++) {
				for (int j = 0; j < imagem[k][i].length; j++) {
					List<Double> valores = new ArrayList<Double>();
					for (int r1 = -raio; r1 <= raio; r1++) {
						for (int r2 = -raio; r2 <= raio; r2++) {
							if (i + r1 >= 0 && i + r1 < imagem[k].length
									&& j + r2 >= 0
									&& j + r2 < imagem[k][i].length) {
								valores.add(imagem[k][i][j]);
							}
						}
					}
					Collections.sort(valores);
					retorno[k][i][j] = valores.get(valores.size() / 2);
				}
			}
		}
		return retorno;
	}
	
	public static double mediana(ArrayList<Double> vals) {
		Collections.sort(vals);
		return vals.get(vals.size()/2);
	}
	
	public static double mediaN(ArrayList<Double> vals, int n) {
		double retorno = 0;
		Collections.sort(vals);
		int conta = 0;
		for(int i = 0; i < n && i < vals.size(); i++) {
			retorno += vals.get(i);
			conta++;
		}
		return retorno/conta;
	}

	public static double[][] mediana(double[][] imagem, int raio) {
		double[][] retorno = new double[imagem.length][imagem[0].length];
		for (int i = 0; i < imagem.length; i++) {
			for (int j = 0; j < imagem[i].length; j++) {
				List<Double> valores = new ArrayList<Double>();
				for (int r1 = -raio; r1 <= raio; r1++) {
					for (int r2 = -raio; r2 <= raio; r2++) {
						if (i + r1 >= 0 && i + r1 < imagem.length
								&& j + r2 >= 0 && j + r2 < imagem[i].length) {
							valores.add(imagem[i][j]);
						}
					}
				}
				Collections.sort(valores);
				retorno[i][j] = valores.get(valores.size() / 2);
			}
		}
		return retorno;
	}
	
	public static double[][] media(double[][] imagem, int raio) {
		double[][] retorno = new double[imagem.length][imagem[0].length];
		for (int i = 0; i < imagem.length; i++) {
			for (int j = 0; j < imagem[i].length; j++) {
				double val = 0;
				for (int r1 = -raio; r1 <= raio; r1++) {
					for (int r2 = -raio; r2 <= raio; r2++) {
						if (i + r1 >= 0 && i + r1 < imagem.length
								&& j + r2 >= 0 && j + r2 < imagem[i].length) {
							val += imagem[i][j];
						}
					}
				}
				retorno[i][j] = val/(Math.pow(raio*2+1,2));
			}
		}
		return retorno;
	}
	
	public static double[][] realceMedia(double[][] imagem, int raio, double a) {
		double[][] retorno = new double[imagem.length][imagem[0].length];
		for (int i = 0; i < imagem.length; i++) {
			for (int j = 0; j < imagem[i].length; j++) {
				double media = 0;
				int cont = 0;
				for (int r1 = -raio; r1 <= raio; r1++) {
					for (int r2 = -raio; r2 <= raio; r2++) {
						if (i + r1 >= 0 && i + r1 < imagem.length
								&& j + r2 >= 0 && j + r2 < imagem[i].length) {
							media += imagem[i][j];
							cont++;
						}
					}
				}
				media = media/cont;
				retorno[i][j] = imagem[i][j] + a*(imagem[i][j]-media);
			}
		}
		return retorno;
	}

	public static double[][][] maximo(double[][][] imagem, int raio) {
		double[][][] retorno = new double[imagem.length][imagem[0].length][imagem[0][0].length];
		for (int k = 0; k < imagem.length; k++) {
			for (int i = 0; i < imagem[k].length; i++) {
				for (int j = 0; j < imagem[k][i].length; j++) {
					double tmp = 0;
					boolean iniciou = false;
					for (int r1 = -raio; r1 <= raio; r1++) {
						for (int r2 = -raio; r2 <= raio; r2++) {
							if (i + r1 >= 0 && i + r1 < imagem[k].length
									&& j + r2 >= 0
									&& j + r2 < imagem[k][i].length) {
								if (!iniciou || tmp < imagem[k][i][j]) {
									tmp = imagem[k][i][j];
								}

							}
						}
					}

					retorno[k][i][j] = tmp;
				}
			}
		}
		return retorno;
	}

	public static double[][] maximo(double[][] imagem, int raio) {
		double[][] retorno = new double[imagem.length][imagem[0].length];
		for (int i = 0; i < imagem.length; i++) {
			for (int j = 0; j < imagem[i].length; j++) {
				double tmp = 0;
				boolean iniciou = false;
				for (int r1 = -raio; r1 <= raio; r1++) {
					for (int r2 = -raio; r2 <= raio; r2++) {
						if (i + r1 >= 0 && i + r1 < imagem.length
								&& j + r2 >= 0 && j + r2 < imagem[i].length) {
							if (!iniciou || tmp < imagem[i][j]) {
								tmp = imagem[i][j];
							}

						}
					}
				}

				retorno[i][j] = tmp;
			}
		}
		return retorno;
	}

	public static double[][] media(List<double[][]> entradas) {
		double[][] retorno = new double[entradas.get(0).length][entradas.get(0)[0].length];
		for (double[][] ds : entradas) {
			for (int i = 0; i < ds.length; i++) {
				for (int j = 0; j < ds[0].length; j++) {
					retorno[i][j] += ds[i][j] / entradas.size();
				}
			}
		}
		return retorno;
	}
	
	public static double[][] mediaImagens(List<Imagem> entradas) {
		double[][] retorno = new double[entradas.get(0).getImagem().length][entradas.get(0).getImagem()[0].length];
		for (Imagem ds : entradas) {
			for (int i = 0; i < ds.getImagem().length; i++) {
				for (int j = 0; j < ds.getImagem()[0].length; j++) {
					retorno[i][j] += ds.getImagem()[i][j] / entradas.size();
				}
			}
		}
		return retorno;
	}

	public static double[][] diferenca(double[][] entrada1, double[][] entrada2) {
		double[][] retorno = new double[entrada1.length][entrada1[0].length];
		for (int i = 0; i < retorno.length; i++) {
			for (int j = 0; j < retorno[0].length; j++) {
				retorno[i][j] = Math.abs(entrada1[i][j] - entrada2[i][j]);
			}
		}
		return retorno;
	}
	
	public static double[][][] subtracao(double[][][] entrada1,
			double[][][] entrada2) {
		double[][][] retorno = new double[entrada1.length][entrada1[0].length][entrada1[0][0].length];
		for (int i = 0; i < retorno.length; i++) {
			for (int j = 0; j < retorno[0].length; j++) {
				for (int k = 0; k < retorno[0][0].length; k++) {
					retorno[i][j][k] = entrada1[i][j][k] - entrada2[i][j][k];
				}
			}
		}
		return retorno;
	}

	public static double[][] subtracao(double[][] entrada1, double[][] entrada2) {
		double[][] retorno = new double[entrada1.length][entrada1[0].length];
		for (int i = 0; i < retorno.length; i++) {
			for (int j = 0; j < retorno[0].length; j++) {
				retorno[i][j] = entrada1[i][j] - entrada2[i][j];
			}
		}
		return retorno;
	}

	public static void subtracao2(double[][][] entrada1, double[][][] entrada2) {
		for (int i = 0; i < entrada1.length; i++) {
			for (int j = 0; j < entrada1[0].length; j++) {
				for (int k = 0; k < entrada1[0][0].length; k++) {
					entrada1[i][j][k] = entrada1[i][j][k] - entrada2[i][j][k];
				}
			}
		}
	}

	
	public static double entropia(ArrayList<double[][]> elementos) {
		double distanciaCentro = 0;
		double entropia = 0;
		int qtdElementos = 0;
		double distMin = 0;
		int centroAtual = -1;
		for (int k = 0; k < elementos.size(); k++) {
			qtdElementos++;
			double distancia = 0;
			for (int l = k + 1; l < elementos.size(); l++) {
				if (l != k) {
					double tmp = UtilImage.distancia2(elementos.get(k),
							elementos.get(l));
					distancia += tmp;
				}
			}
			entropia += distancia;
			if (centroAtual == -1 || distancia < distMin) {
				centroAtual = k;
				distMin = distancia;
				distanciaCentro = distancia;
			}
		}

		entropia = entropia / qtdElementos;
		distanciaCentro = distanciaCentro / qtdElementos;
		return entropia;
	}

	public static ArrayList<double[][]> divideImagem(int tamanho,
			double[][] imagem) throws Exception {
		try {
			ArrayList<double[][]> retorno = new ArrayList<double[][]>();
			for (int i = 0; i < imagem.length / tamanho; i++) {
				for (int j = 0; j < imagem[0].length / tamanho; j++) {
					double[][] imagemTmp = new double[tamanho][tamanho];
					for (int a = 0; a < tamanho; a++) {
						for (int b = 0; b < tamanho; b++) {
							imagemTmp[a][b] = imagem[i * tamanho + a][j
									* tamanho + b];
						}
					}
					retorno.add(imagemTmp);
				}
			}
			return retorno;
		} catch (Exception e) {
			System.out.println("Erro");
			e.printStackTrace();
			return null;
		}
	}

	public static double[][] normaliza(double[][] imagem, double novoMax) {
		double min = imagem[0][0];
		double max = imagem[0][0];
		for (int i = 0; i < imagem.length; i++) {
			for (int j = 0; j < imagem[0].length; j++) {
				if(imagem[i][j] > max) {
					max = imagem[i][j];
				}
				if(imagem[i][j] < min) {
					min = imagem[i][j];
				}
			}
		}
		double[][] retorno = new double[imagem.length][imagem[0].length];
		for (int i = 0; i < imagem.length; i++) {
			for (int j = 0; j < imagem[0].length; j++) {
				retorno[i][j] = (imagem[i][j]-min)/(max-min)*novoMax;
			}
		}
		return retorno;
	}
	
	public static double[][] equaliza(double[][] imagem) {
		try {
			double[] histograma = new double[256];
			double[] histogramaCumulativo = new double[256];
			// Calculando o histograma
			for (int i = 0; i < imagem.length; i++) {
				for (int j = 0; j < imagem[0].length; j++) {
					histograma[new Double(imagem[i][j]).intValue()]++;
				}
			}

			// Calculando o histograma acumulado
			double acumulado = histograma[0];
			for (int i = 0; i < histograma.length - 1; i++) {
				histogramaCumulativo[i] = acumulado;
				acumulado = acumulado + histograma[i + 1];
			}
			histogramaCumulativo[histograma.length - 1] = acumulado;

			// Equalizando o histograma
			for (int i = 0; i < histogramaCumulativo.length; i++) {
				histogramaCumulativo[i] = (histogramaCumulativo[i] / new Integer(
						imagem.length * imagem[0].length).doubleValue()) * 255.0;
			}
			// 370 123
			// Modificando imagem
			for (int i = 0; i < imagem.length; i++) {
				for (int j = 0; j < imagem[0].length; j++) {
					imagem[i][j] = histogramaCumulativo[new Double(imagem[i][j])
							.intValue()];
				}
			}

			return imagem;

		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	public static BufferedImage rotate(BufferedImage image, int angulo) {
		BufferedImage aimg = new BufferedImage(image.getWidth(),
				image.getHeight(), image.getType());
		Graphics2D g2d = (Graphics2D) aimg.getGraphics();
		AffineTransform origXform = g2d.getTransform();
		AffineTransform newXform = (AffineTransform) (origXform.clone());

		int width = image.getWidth();
		int height = image.getHeight();

		// center of rotation is center of the panel
		int xRot = width / 2;
		int yRot = height / 2;
		newXform.rotate(Math.toRadians(angulo), xRot, yRot);
		g2d.setTransform(newXform);
		g2d.drawImage(image, null, 0, 0);
		g2d.setTransform(origXform);
		return aimg;
	}

	public static BufferedImage espelho(BufferedImage image) {
		BufferedImage aimg = new BufferedImage(image.getWidth(),
				image.getHeight(), image.getType());

		for (int y = 0; y < aimg.getHeight(); ++y) {
			for (int x = 0; x < aimg.getWidth(); ++x) {
				double[] tmp = new double[1];
				image.getRaster().getPixel((image.getWidth() - 1) - x, y, tmp);
				aimg.getRaster().setPixel(x, y, tmp);
			}
		}
		return aimg;
	}

	public static double fatorial(int n) {
		double retorno = 1;
		for (; n > 1; n--) {
			retorno = retorno * n;
		}
		return retorno;
	}

	public static double erlang(double z) {
		double a = 0.1;
		int b = 2;
		// double z = 10;
		// System.out.println((b-1.0)/a);
		return Math.pow(a, b) * Math.pow(z, b - 1) * Math.exp(-(a * z))
				/ UtilImage.fatorial(b - 1);
	}

	public static void carregaImagemRedimensionaMudaFundoSalva(String imagem,
			String valida) throws Exception {
		BufferedImage image = ImageIO.read(new File(imagem));

	}
	
	public static double[][] uniformiza(double[][] imagem) {
		double max = imagem[0][0];
		for (int i = 0; i < imagem.length; i++) {
			for (int j = 0; j < imagem[i].length; j++) {
				if(imagem[i][j] > max) {
					max = imagem[i][j];
				}
			}
		}
		double[][] retorno = new double[imagem.length][imagem[0].length];
		for (int i = 0; i < imagem.length; i++) {
			for (int j = 0; j < imagem[i].length; j++) {
				retorno[i][j] = (imagem[i][j]/max)*255;
			}
		}
		return retorno;
	}

	public static void pintaCinzaNormaliza(String caminho, double[][] imagem)
			throws Exception {
		imagem = normaliza(imagem,255);
		try {
			BufferedImage image2 = new BufferedImage(imagem[0].length,
					imagem.length, BufferedImage.TYPE_BYTE_GRAY);
			for (int y = 0; y < imagem.length; ++y) {
				for (int x = 0; x < imagem[0].length; ++x) {
					// System.out.println(tmp[0]+" | "+tmp[0]/256000);
					double[] tmp = new double[] { imagem[y][x] };
					image2.getRaster().setPixel(x, y, tmp);
				}
			}
			ImageIO.write(image2, "bmp", new File(caminho));

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
}
